#include "balloc.h"

// Structure used to register allocated blocks
typedef struct Register_Tag {
    struct Register_Tag *next; // Next registered block
    void *ptr; // Pointer to the allocated block
    char *who; // Caller file name
    int where; // Caller line number
} Register;

// Linked list head. Field 'where' will be used as a counter for registered blocks.
Register head = {NULL,NULL,0};

// Auxiliary
void auxfree(Register **p) {
    Register *q = *p;
    *p = q->next;
    free(q->ptr);
    free(q);
    head.where--;
    return;
}

// API implementation
void *balloc(char *who, int where, size_t n) {
    void *p;
    Register *r = (Register *)malloc(sizeof(Register));
    if (r==NULL) return NULL;
    p = malloc(n);
    if (p==NULL) {
        free(r);
        return NULL;
    }
    r->next = head.next;
    r->ptr = p;
    r->who = who;
    r->where = where;
    head.next = r;
    head.where++;
    return p;
}

int bfree(void *ptr) {
    Register **p;
    if (ptr==NULL) return 1; // Attempt to free a NULL pointer
    for (p=&(head.next); (((*p)!=NULL)&&(((*p)->ptr)!=ptr)); p=&((*p)->next)) {
        // advance through the list
    }
    if ((*p)==NULL) return 2; // Attempt to free an unregistered pointer 
    auxfree(p);
    return 0; // OK
}

int bnextfree(char **who, int *where) {
    Register *p = head.next;
    if (p==NULL) return 1;
    *who = p->who;
    *where = p->where;
    auxfree(&(head.next));
    return 0;
}

void bfreeall() {
    while (head.next!=NULL) auxfree(&(head.next));
}

int bcheck() {
    return head.where;
}

void bapply(bfunc *bf) {
    Register *p;
    for (p=head.next;p!=NULL;p=p->next)
        bf(p->who,p->where,p->ptr);
}
